package org.nemanjaristic.utils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.nemanjaristic.extensions.jena.vocabulary.OPO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.code.facebookapi.schema.User;
import com.google.code.facebookapi.schema.UserStatus;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.sparql.vocabulary.FOAF;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;

import de.fuberlin.wiwiss.ng4j.NamedGraphSet;
import de.fuberlin.wiwiss.ng4j.db.NamedGraphSetDB;

public class RDFUtils {

	private static Logger logger = LoggerFactory.getLogger(RDFUtils.class);
	private static final String NS = "http://opo.rs/";

	private Model m;

	public RDFUtils() {}

	public Model createRDFModel() {
		NamedGraphSet set = new NamedGraphSetDB(ConnectionUtils.getConnection());
		m = set.asJenaModel("http://example.org/defaultgraph");
		logger.info("Model created.");
		return m;
	}

	public Writer createModelWriter(String fileName) {
		Writer writer = null;
		try {
			writer = new OutputStreamWriter(new FileOutputStream(new File(fileName)), "UTF-8");
		}
		catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		return writer;
	}

	public void populateModel(List<User> users) {
		for (User user : users) {
			addUserToModel(user);
		}
	}

	public List<User> populateUsersFromDB() {
		List<User> users = new ArrayList<User>();
		ResIterator iterator = m.listSubjectsWithProperty(RDF.type);
		while (iterator.hasNext()) {
			Resource node = iterator.next();
			User user = convertResourceToUser(node);
			users.add(user);
		}
		logger.debug("Selected users from repository: {}", users.size());
		return users;
	}

	private void addUserToModel(User user) {
		Resource person = m.createResource();
		person = m.createResource(NS + user.getUid());
		person.addProperty(RDF.type, FOAF.Person);
		if (user.getFirstName() != null) {
			person.addProperty(FOAF.firstName, user.getFirstName());
		}
		if (user.getName() != null)
			person.addProperty(FOAF.name, user.getName());
		if (user.getStatus() != null)
			person.addProperty(OPO.customMessage, user.getStatus().getMessage());
		if (user.getBirthday() != null)
			person.addProperty(FOAF.birthday, user.getBirthday());
		if (user.getProfileUrl() != null)
			person.addProperty(FOAF.holdsAccount, user.getProfileUrl());
		if (user.getPic() != null)
			person.addProperty(FOAF.img, user.getPic());
	}

	private User convertResourceToUser(Resource node) {
		User user = new User();
		if (node.getProperty(FOAF.firstName) != null)
			user.setFirstName(node.getProperty(FOAF.firstName).getString());
		if (node.getProperty(FOAF.name) != null)
			user.setName(node.getProperty(FOAF.name).getString());
		if (node.getProperty(OPO.customMessage) != null) {
			UserStatus us = new UserStatus();
			us.setMessage(node.getProperty(OPO.customMessage).getString());
			user.setStatus(us);
		}
		if (node.getProperty(FOAF.birthday) != null)
			user.setBirthday(node.getProperty(FOAF.birthday).getString());
		if (node.getProperty(FOAF.img) != null)
			user.setPic(node.getProperty(FOAF.img).getString());
		return user;
	}

	/**
	 * Updates user (keeps property and add new one with same name)
	 */
	public void updateUser() {
		Resource resource = m.createResource("http://nemanjaristic.org/");
		resource.addProperty(FOAF.holdsAccount, "new account");
		resource.addProperty(OPO.currentLocation, "Belgrade");
	}

	/**
	 * Update user(removes property and add a new property)
	 */
	public void updateUserWithRemove() {
		Resource resource = m.createResource("http://nemanjaristic.org/");
		resource.removeAll(FOAF.holdsAccount);
		resource.addProperty(FOAF.holdsAccount, "ngšđčć");
		// resource.addProperty(OPO.currentLocation, "Belgrade");
	}

	public void writeModelToFile(Writer writer, String lang) {

		m.setNsPrefix("ex", NS);
		m.setNsPrefix("rdf", RDF.getURI());
		m.setNsPrefix("rdfs", RDFS.getURI());
		m.setNsPrefix("foaf", FOAF.getURI());
		m.setNsPrefix("opo", OPO.getURI());

		m.write(writer, lang);
	}

	public void exampleDB() throws ClassNotFoundException, SQLException {
		Resource resource = m.createResource("http://nemanjaristic.org/");
		resource.addProperty(RDF.type, FOAF.Person);
		resource.removeAll(FOAF.holdsAccount);
		resource.addProperty(FOAF.name, "čćčpšđ");
		ResIterator iterator = m.listSubjectsWithProperty(RDF.type);
		while (iterator.hasNext()) {
			Resource node = iterator.next();
			User user = convertResourceToUser(node);
			System.out.println(user.getName());
		}
	}

	public static void main(String[] args) throws ClassNotFoundException, SQLException {

		RDFUtils u = new RDFUtils();
		u.createRDFModel();
		u.exampleDB();
		// u.updateUserWithRemove();
	}
}
